/*
 * OpenParts
 * A dynamic-loading components framework for GWT
 * Copyright (C) 2011 Christophe Bouthier  [chris{AT}binary-gastronome{DOT}fr]
 *
 * This work is partially based on work I have done at INRIA (http://www.inria.fr) 
 * in the context of the Qualipso European Project (http://qualipso.org/),
 * The work done at INRIA is Copyright (C) 2006-2011 INRIA
 *
 * This work is distributed under the LGPL version 3
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation. See the GNU
 * Lesser General Public License in LGPL.txt for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package fr.openparts.OpenParts.test.gwt.tests;

import com.google.gwt.junit.client.GWTTestCase;

import fr.openparts.OpenParts.client.OPBinding;
import fr.openparts.OpenParts.client.OPBindingAction;
import fr.openparts.OpenParts.client.OPBindingResource;
import fr.openparts.OpenParts.client.OPBindingService;
import fr.openparts.OpenParts.client.OPShell;

/**
 * GWT tests for the tree of data (service, resource, action) of OPBinding.
 * 
 * @author Christophe Bouthier [chris{AT}binary-gastronome{DOT}fr]
 * @creation.date 22 December 2009
 */
public class OPSharedBindingDataTreeTestGwt extends GWTTestCase {

    private static final String SERVICE_NAME = "serviceName";
    private static final String RESOURCE_NAME = "resourceName";
    private static final String ACTION_NAME = "actionName";

    private OPBinding binding;
    private OPBindingService service;
    private OPBindingResource resource;
    private OPBindingAction action;

    /**
     * Return the name of the tested GWT Module.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#getModuleName()
     */
    @Override
    public final String getModuleName() {
        return "fr.openparts.OpenParts.test.gwt.TestOpenParts";
    }

    /**
     * Called before each test, set up the binding.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#gwtSetUp()
     */
    @Override
    protected final void gwtSetUp() throws Exception {
        super.gwtSetUp();
        binding = OPShell.opBindingSharedInstance();
        service = OPBindingService.serviceFactory(SERVICE_NAME);
        resource = OPBindingResource.resourceFactory(RESOURCE_NAME);
        action = OPBindingAction.actionFactory(ACTION_NAME);

        binding.bind(service);
        service.bindResource(resource);
        resource.bindAction(action);
    }

    /**
     * Called at the end of each test to clean up the mess.
     * 
     * @see com.google.gwt.junit.client.GWTTestCase#gwtTearDown()
     */
    @Override
    protected final void gwtTearDown() throws Exception {
        super.gwtTearDown();
        emptyServices(binding);
    }

    /**
     * Test getting all names of binded services. Should get the corresponding array.
     */
    public final void testGettingServicesNames() {
        final String[] servicesNames = binding.getServicesNames();
        assertNotNull("Names array shouldn't be null", servicesNames);
        assertEquals("Names array should contains only 1 element", 1, servicesNames.length);
        assertEquals("Element of name array should be the service", SERVICE_NAME, servicesNames[0]);
    }

    /**
     * Test getting all names of binded services without services binded. Should get an empty but not null array.
     */
    public final void testGettingServicesNamesWithoutServices() {
        emptyServices(binding);
        final String[] servicesNames = binding.getServicesNames();
        assertNotNull("Names array shouldn't be null", servicesNames);
        assertEquals("Names array should be empty", 0, servicesNames.length);
    }

    /**
     * Test getting back a binded service. Should get service.
     */
    public final void testGettingService() {
        final OPBindingService bindedService = binding.getService(SERVICE_NAME);
        assertNotNull("binded service shouldn't be null", bindedService);
        assertEquals("Should get back the same binded service.", service, bindedService);
    }

    /**
     * Test getting an inexistent service. Should get null.
     */
    public final void testGettingInexistentService() {
        assertNull("Inexistent service should be null", binding.getService("INEXISTENT_SERVICE"));
    }

    /**
     * Test getting a service passing a null service name. Should raise an assertion error.
     */
    public final void testGettingServiceWithNullName() {
        if (assertionsAreEnabled()) {
            try {
                binding.getService(null);
                fail("OPBinding should raise an assertion error when getting service with a null service name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting back a binded resource. Should get resource.
     */
    public final void testGettingResource() {
        final OPBindingResource bindedResource = binding.getResource(SERVICE_NAME, RESOURCE_NAME);
        assertNotNull("binded resource shouldn't be null", bindedResource);
        assertEquals("Should get back the same binded resource.", resource, bindedResource);
    }

    /**
     * Test getting an inexistent resource. Should get null.
     */
    public final void testGettingInexistentResource() {
        assertNull("Inexistent resource should be null", binding.getResource(SERVICE_NAME, "INEXISTENT_RESOURCE"));
    }

    /**
     * Test getting a resource for an inexistent service. Should get null.
     */
    public final void testGettingResourceWithInexistentService() {
        assertNull("Resource for inexistent service should be null", binding.getResource("INEXISTENT_SERVICE", RESOURCE_NAME));
    }

    /**
     * Test getting a resource passing a null service name. Should raise an assertion error.
     */
    public final void testGettingResourceWithNullServiceName() {
        if (assertionsAreEnabled()) {
            try {
                binding.getResource(null, RESOURCE_NAME);
                fail("OPBinding should raise an assertion error when getting resource with a null service name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting a resource passing a null resource name. Should raise an assertion error.
     */
    public final void testGettingResourceWithNullResourceName() {
        if (assertionsAreEnabled()) {
            try {
                binding.getResource(SERVICE_NAME, null);
                fail("OPBinding should raise an assertion error when getting resource with a null resource name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting back a binded action. Should get action.
     */
    public final void testGettingAction() {
        final OPBindingAction bindedAction = binding.getAction(SERVICE_NAME, RESOURCE_NAME, ACTION_NAME);
        assertNotNull("binded action shouldn't be null", bindedAction);
        assertEquals("Should get back the same binded action.", action, bindedAction);
    }

    /**
     * Test getting an inexistent action. Should get null.
     */
    public final void testGettingInexistentAction() {
        assertNull("Inexistent action should be null", binding.getAction(SERVICE_NAME, RESOURCE_NAME, "INEXISTENT_ACTION"));
    }

    /**
     * Test getting an action for an inexistent service. Should get null.
     */
    public final void testGettingActionWithInexistentService() {
        assertNull("Action for inexistent service should be null", binding.getAction("INEXISTENT_SERVICE", RESOURCE_NAME, ACTION_NAME));
    }

    /**
     * Test getting an action for an inexistent resource. Should get null.
     */
    public final void testGettingActionWithInexistentResource() {
        assertNull("Action for inexistent resource should be null", binding.getAction(SERVICE_NAME, "INEXISTENT_RESOURCE", ACTION_NAME));
    }

    /**
     * Test getting an action passing a null service name. Should raise an assertion error.
     */
    public final void testGettingActionWithNullServiceName() {
        if (assertionsAreEnabled()) {
            try {
                binding.getAction(null, RESOURCE_NAME, ACTION_NAME);
                fail("OPBinding should raise an assertion error when getting action with a null service name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting an action passing a null resource name. Should raise an assertion error.
     */
    public final void testGettingActionWithNullResourceName() {
        if (assertionsAreEnabled()) {
            try {
                binding.getAction(SERVICE_NAME, null, ACTION_NAME);
                fail("OPBinding should raise an assertion error when getting action with a null resource name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test getting an action passing a null action name. Should raise an assertion error.
     */
    public final void testGettingActionWithNullActionName() {
        if (assertionsAreEnabled()) {
            try {
                binding.getAction(SERVICE_NAME, RESOURCE_NAME, null);
                fail("OPBinding should raise an assertion error when getting action with a null action name.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test binding a null service. Should raise an assertion error.
     */
    public final void testBindingNullService() {
        if (assertionsAreEnabled()) {
            try {
                binding.bind((OPBindingService) null);
                fail("OPBinding should raise an assertion error when binding a null service.");
            } catch (AssertionError e) {
                assertTrue("Error should be an AssertionError", e instanceof AssertionError);
            }
        }
    }

    /**
     * Test binding two services with the same name. Should return only the second service.
     */
    public final void testReBindingSameService() {
        final OPBindingService service2 = OPBindingService.serviceFactory(SERVICE_NAME);
        assertNotSame("services shouldn't be the same", service, service2);
        binding.bind(service2);
        assertEquals("Should get the latest binded service", service2, binding.getService(SERVICE_NAME));
    }

    /**
     * Native helper method to clean up view factories.
     */
    private final native void emptyServices(final OPBinding binding) /*-{
        binding.services = {};
    }-*/;

    /**
     * Check if assertions are enabled.
     * 
     * @return true if assertions are enabled, false otherwise
     */
    private final boolean assertionsAreEnabled() {
        try {
            assert false;
            return false;
        } catch (AssertionError e) {
            return true;
        }
    }

}
